#include <../lib/igloo/igloo.h>
#include "../../HashExtensible/Cubeta.h"
#include "../../HashExtensible/RegistroCubeta.h"

using namespace igloo;
using namespace Hash;

Context(CubetaTest) {
	Cubeta* cubeta;
	RegistroCubeta* registroCubeta;
	RegistroCubeta* registroCubeta2;

	void SetUp() {
		cubeta = new Cubeta(1, 100);
		registroCubeta  = new RegistroCubeta("091011Presidente", 10);
		registroCubeta2 = new RegistroCubeta("311211Presidente", 20);

	}

	void TearDown() {
		delete registroCubeta;
		delete registroCubeta2;
		delete cubeta;
	}

	Spec(tamanioBuffer) {
		unsigned int tamanio = cubeta->getTamanioDelBuffer();
		Assert::That(tamanio, Is().EqualTo(12));
	}

	Spec(insertar) {
		cubeta->insertar(*registroCubeta);
		Assert::That(cubeta->getTamanioDelBuffer(), Is().EqualTo(40));
	}

	Spec(insertarDosregistros) {
			cubeta->insertar(*registroCubeta);
			cubeta->insertar(*registroCubeta2);
			Assert::That(cubeta->getTamanioDelBuffer(), Is().EqualTo(68));
			Assert::That(cubeta->getBytesLibres(), Is().EqualTo(32));
	}

	Spec(insertarConDesborde) {
		RegistroCubeta* registroCubeta3 = new RegistroCubeta("030711Presidente", 45);

		EstadoCubeta estado  = cubeta->insertar(*registroCubeta);
		EstadoCubeta estado2 = cubeta->insertar(*registroCubeta2);
		EstadoCubeta estado3 = cubeta->insertar(*registroCubeta3);

		Assert::That(estado, Is().EqualTo(OK));
		Assert::That(estado2, Is().EqualTo(OK));
		Assert::That(estado3, Is().EqualTo(LLENO));

		delete registroCubeta3;

		Assert::That(cubeta->getTamanioDelBuffer(), Is().EqualTo(68));
	}

	Spec(insertarNuevoOffSetConClaveExistente) {
		RegistroCubeta* registroCubeta3 = new RegistroCubeta("091011Presidente", 45);

		cubeta->insertar(*registroCubeta);
		cubeta->insertar(*registroCubeta3);

		Assert::That(cubeta->getTamanioDelBuffer(), Is().EqualTo(44));
		Assert::That(cubeta->getBytesLibres(), Is().EqualTo(56));

		delete registroCubeta3;
	}

	Spec(insertarConDesbordePorOffset) {
		RegistroCubeta* registroCubeta3 = new RegistroCubeta("311211Presidente", 88);

		cubeta->insertar(*registroCubeta);//28
		cubeta->insertar(*registroCubeta3);//56
		Assert::That(cubeta->getBytesLibres(), Is().EqualTo(32));

		delete registroCubeta3;
		registroCubeta3 = new RegistroCubeta("", 45);

		EstadoCubeta estado = cubeta->insertar(*registroCubeta3);//80
		Assert::That(estado, Is().EqualTo(OK));
		Assert::That(cubeta->getBytesLibres(), Is().EqualTo(20));
		delete registroCubeta3;

		//sigo insertando offsets hasta saturarlo
		registroCubeta3 = new RegistroCubeta("311211Presidente", 36);
		cubeta->insertar(*registroCubeta3);//+4
		delete registroCubeta3;

		registroCubeta3 = new RegistroCubeta("311211Presidente", 37);
		cubeta->insertar(*registroCubeta3);//+4
		delete registroCubeta3;

		registroCubeta3  = new RegistroCubeta("311211Presidente", 38);
		cubeta->insertar(*registroCubeta3);//+4
		delete registroCubeta3;

		registroCubeta3  = new RegistroCubeta("311211Presidente", 56);
		cubeta->insertar(*registroCubeta3);//+4
		delete registroCubeta3;

		registroCubeta3 = new RegistroCubeta("311211Presidente", 76);
		cubeta->insertar(*registroCubeta3);//+4
		delete registroCubeta3;

		Assert::That(cubeta->getBytesLibres(), Is().EqualTo(0));

		registroCubeta3 = new RegistroCubeta("311211Presidente", 96);
		estado = cubeta->insertar(*registroCubeta3);
		Assert::That(estado, Is().EqualTo(LLENO));
		Assert::That(registroCubeta3->getOffsets()->size(), Is().EqualTo(7));
		Assert::That(cubeta->getRegistros()->size(), Is().EqualTo(2));
		delete registroCubeta3;

		//inserto una clave que ya inserté
		registroCubeta3  = new RegistroCubeta("091011Presidente", 10);
		estado = cubeta->insertar(*registroCubeta3);//+4
		Assert::That(estado, Is().EqualTo(SINACCION));

		delete registroCubeta3;
	}

	Spec(eliminar){
		cubeta->insertar(*registroCubeta);
		cubeta->insertar(*registroCubeta2);

		RegistroCubeta* registroCubeta3  = new RegistroCubeta("091011Presidente", 10);
		cubeta->eliminar(registroCubeta3);
		Assert::That(cubeta->getBytesLibres(), Is().EqualTo(60));

		delete registroCubeta3;
	}

	Spec(eliminarInexistente){
		cubeta->insertar(*registroCubeta);

		EstadoCubeta estado = cubeta->eliminar(registroCubeta2);
		Assert::That(estado, Is().EqualTo(SINACCION));
	}

	Spec(eliminarOffset){
		RegistroCubeta* registroCubeta3  = new RegistroCubeta("091011Presidente", 20);

		cubeta->insertar(*registroCubeta);
		cubeta->insertar(*registroCubeta3);
		Assert::That(cubeta->getRegistros()->size(), Is().EqualTo(1));
		Assert::That(cubeta->getBytesOcupados(), Is().EqualTo(44));

		delete registroCubeta3;
		registroCubeta3  = new RegistroCubeta("091011Presidente", 20);
		cubeta->eliminar(registroCubeta3);
		Assert::That(cubeta->getRegistros()->size(), Is().EqualTo(1));
		Assert::That(cubeta->getBytesOcupados(), Is().EqualTo(40));
		Assert::That(cubeta->getBytesLibres(), Is().EqualTo(60));

		delete registroCubeta3;
	}

	Spec(eliminarCubetaQuedaVacia){
		cubeta->insertar(*registroCubeta);
		cubeta->insertar(*registroCubeta2);

		RegistroCubeta* registroCubeta3  = new RegistroCubeta("091011Presidente", 10); //igual al 1
		cubeta->eliminar(registroCubeta3);
		delete registroCubeta3;

		registroCubeta3 = new RegistroCubeta("311211Presidente", 20); //igual al 2
		EstadoCubeta estado = cubeta->eliminar(registroCubeta3);
		Assert::That(estado, Is().EqualTo(VACIO));
		Assert::That(cubeta->getBytesOcupados(), Is().EqualTo(12));
		Assert::That(cubeta->getBytesLibres(), Is().EqualTo(88));

		delete registroCubeta3;
	}

	Spec(buscar){
		cubeta->insertar(*registroCubeta);
		int posicion = cubeta->buscar("091011Presidente");
		Assert::That(posicion, Is().EqualTo(0));
	}

	Spec(buscarInexistente){
		cubeta->insertar(*registroCubeta);
		int posicion = cubeta->buscar("091010Concejal");
		Assert::That(posicion, Is().EqualTo(-1));
	}

};
